import { djb2HashCode } from "./hashCodeFunction.js";
import ValuePair from "../dictionary/ValuePair.js";

export default class HashTable {
  constructor() {
    this.table = {};
  }

  /**
   * 计算hash code
   * @param {string} key
   * @returns {number}
   */
  hashCode(key) {
    return djb2HashCode(key);
  }

  /**
   * 向散列表添加或更新新值
   * @param {string} key
   * @param {*} value
   * @returns {HashTable}
   */
  put(key, value) {
    if (key == null || value == null) {
      return this;
    }

    const position = this.hashCode(key);
    this.table[position] = new ValuePair(key, value);
    return this;
  }

  /**
   * 获取散列表中的值
   * @param {string} key
   * @returns {*}
   */
  get(key) {
    const result = this.table[this.hashCode(key)];
    return result ? result.value : null;
  }

  /**
   * 移除散列表中的值
   * @param {string} key
   * @returns {boolean}
   */
  remove(key) {
    const hash = this.hashCode(key);
    const valuePair = this.table[hash];
    if (valuePair != null) {
      delete this.table[hash];
      return true;
    }
    return false;
  }

  /**
   * 查询散列表中是否存在此key
   * @param {string} key
   * @returns {boolean}
   */
  hasKey(key) {
    return this.table[this.hashCode(key)] != null;
  }

  /**
   * 返回散列表的大小
   * @returns {number}
   */
  size() {
    return Object.keys(this.table).length;
  }

  /**
   * 查询散列表是否为空
   * @returns {boolean}
   */
  isEmpty() {
    return this.size() === 0;
  }

  /**
   * 清空散列表
   */
  clear() {
    this.table = {};
  }

  /**
   * 返回字典的字符串形式
   * @param {function} callback 回调函数支持两个参数：key, value
   * @returns {string}
   */
  toString(callback) {
    const keys = Object.keys(this.table);
    let result = "[";
    for (let i = 0; i < keys.length; i++) {
      result += `{ ${keys[i]} => ${this.table[keys[i]].toString(callback)} }`;
      if (i < keys.length - 1) {
        result += ",\n";
      }
    }
    result += "]";
    return result;
  }
}
